wayland: create a wl_subsurface interface for GDK_WINDOW_SUBSURFACE windows
authorCarlos Garnacho <carlosg@gnome.org>
Thu, 21 Aug 2014 15:31:50 +0000 (17:31 +0200)
committerCarlos Garnacho <carlosg@gnome.org>
Tue, 26 Aug 2014 10:58:13 +0000 (12:58 +0200)
This subsurface is currently dependent on the transient_for parent, so the
subsurface is repositioned relative to it.

https://bugzilla.gnome.org/show_bug.cgi?id=729215

gdk/wayland/gdkwindow-wayland.c

index 055352227e7242b46b2496e50a91ebb48f28e552..9c29b96a2cb4e97b5d12527814aa157a434db983 100644 (file)
@@ -95,6 +95,8 @@ struct _GdkWindowImplWayland
   struct xdg_popup   *xdg_popup;
   struct gtk_surface *gtk_surface;
 
+  struct wl_subsurface *subsurface;
+
   unsigned int mapped : 1;
   unsigned int use_custom_surface : 1;
   unsigned int pending_commit : 1;
@@ -784,6 +786,37 @@ static const struct wl_surface_listener surface_listener = {
   surface_leave
 };
 
+static void
+gdk_wayland_window_create_subsurface (GdkWindow *window)
+{
+  GdkWindowImplWayland *impl, *parent_impl = NULL;
+  GdkWaylandDisplay *display_wayland;
+
+  if (GDK_WINDOW_TYPE (window) != GDK_WINDOW_SUBSURFACE)
+    return;
+
+  impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
+
+  if (!impl->surface)
+    return; /* Bail out, surface and subsurface will be created later when shown */
+
+  if (impl->subsurface)
+    return;
+
+  if (impl->transient_for)
+    parent_impl = GDK_WINDOW_IMPL_WAYLAND (impl->transient_for->impl);
+
+  if (parent_impl)
+    {
+      display_wayland = GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
+      impl->subsurface =
+        wl_subcompositor_get_subsurface (display_wayland->subcompositor,
+                                         impl->surface, parent_impl->surface);
+      wl_subsurface_set_position (impl->subsurface, window->x, window->y);
+      wl_subsurface_set_desync (impl->subsurface);
+    }
+}
+
 static void
 gdk_wayland_window_create_surface (GdkWindow *window)
 {
@@ -796,6 +829,9 @@ gdk_wayland_window_create_surface (GdkWindow *window)
 
   gdk_wayland_window_sync_opaque_region (window);
   gdk_wayland_window_sync_input_region (window);
+
+  if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_SUBSURFACE)
+    gdk_wayland_window_create_subsurface (window);
 }
 
 static void
@@ -1070,7 +1106,8 @@ gdk_wayland_window_map (GdkWindow *window)
       else
         transient_for = impl->transient_for;
 
-      if (transient_for)
+      if (transient_for &&
+          GDK_WINDOW_TYPE (window) != GDK_WINDOW_SUBSURFACE)
         {
           struct wl_seat *grab_input_seat = find_grab_input_seat (window, transient_for);
           if (grab_input_seat &&
@@ -1083,7 +1120,8 @@ gdk_wayland_window_map (GdkWindow *window)
             }
         }
 
-      gdk_wayland_window_create_xdg_surface (window);
+      if (GDK_WINDOW_TYPE (window) != GDK_WINDOW_SUBSURFACE)
+        gdk_wayland_window_create_xdg_surface (window);
 
     mapped:
       impl->mapped = TRUE;
@@ -1099,6 +1137,9 @@ gdk_wayland_window_show (GdkWindow *window,
   if (!impl->surface)
     gdk_wayland_window_create_surface (window);
 
+  if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_SUBSURFACE)
+    gdk_wayland_window_create_subsurface (window);
+
   gdk_wayland_window_map (window);
 
   _gdk_make_event (window, GDK_MAP, NULL, FALSE);
@@ -1125,6 +1166,12 @@ gdk_wayland_window_hide_surface (GdkWindow *window)
           impl->xdg_popup = NULL;
         }
 
+      if (impl->subsurface)
+        {
+          wl_subsurface_destroy (impl->subsurface);
+          impl->subsurface = NULL;
+        }
+
       wl_surface_destroy (impl->surface);
       impl->surface = NULL;
 
@@ -1205,11 +1252,18 @@ gdk_window_wayland_move_resize (GdkWindow *window,
 {
   if (with_move)
     {
+      GdkWindowImplWayland *impl;
+
+      impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
+
       /* Each toplevel has in its own "root" coordinate system */
       if (GDK_WINDOW_TYPE (window) != GDK_WINDOW_TOPLEVEL)
         {
           window->x = x;
           window->y = y;
+
+          if (impl->subsurface)
+            wl_subsurface_set_position (impl->subsurface, x, y);
         }
     }
 
@@ -1502,6 +1556,18 @@ gdk_wayland_window_set_transient_for (GdkWindow *window,
   impl->transient_for = parent;
 
   gdk_wayland_window_sync_parent (window);
+
+  if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_SUBSURFACE)
+    {
+      if (impl->subsurface)
+        {
+          wl_subsurface_destroy (impl->subsurface);
+          impl->subsurface = NULL;
+        }
+
+      if (parent)
+        gdk_wayland_window_create_subsurface (window);
+    }
 }
 
 static void